package cn.com.ccxe.dao;

import static cn.com.ccxe.core.util.StringUtil.isEmpty;

import java.sql.ResultSet;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.ccxe.dao.parser.ResultSetParser;

import com.ccxe.manage.db.CcxDB;
import com.ccxe.manage.db.DBFactory;
import com.ccxe.manage.service.transaction.TransactionCcxDb;

public abstract class DBHandler {

	private static final Logger logger = LoggerFactory.getLogger(DBHandler.class);
	
	/**
	 * 执行<b>插入、修改或删除</b>操作，
	 * @param sql 
	 * 			SQL语句，不能为空，如果为空就抛出{@link NullPointerException}
	 * @param parametes
	 * 			传入的参数，需根据SQL语句的顺序，设定参数的排列顺序。
	 * @return
	 */
	protected OperationStatus insertOrUpdateOrDelete(String sql, Object[] parameters) {
		//Tips：未对parametes进行验证
		if (!isEmpty(sql) ) {
			logger.error("没有可执行的语句！");
			throw new NullPointerException();
		}
		if(parameters != null) {
			logger.debug("SQL:"+ sql +"[parameters:"+ objectToString(parameters)+"]");		
		}else {
			logger.debug("sql:"+sql);
		}
		return executeUpdate(sql, parameters);
	}
	
	
	/**
	 * 执行<b>插入、修改或删除</b>操作，
	 * @param sql 
	 * 			SQL语句，不能为空，如果为空就抛出{@link NullPointerException}
	 * @param parametes
	 * 			传入的参数，需根据SQL语句的顺序，设定参数的排列顺序。
	 * @return
	 */
	protected OperationStatus multipleInsertOrUpdateOrDelete(Map<String,Object[]> statements) {
		//TIPS：未对statements中的数据进行验证
		if (statements.size() == 0 ) {
			logger.error("没有可执行的语句！");
			throw new NullPointerException();
		}
		return multipleExecute(statements);
	}

	/**
	 * 调用{@link TransactionCcxDb#dispatch(String, Object[])}进行处理
	 * @param sql 
	 * @param parametes
	 * @return
	 */
	private OperationStatus executeUpdate(String sql, Object[] parametes) {
		TransactionManager transactionManager = null;
		CcxDB db = getCcxDB();
		try {
			if(db == null) {
				throw new NullPointerException("获取数据库实例失败！");
			}
			transactionManager = new TransactionManager(db);
			return transactionManager.execute(sql, parametes);
		} finally {
			close(db);
		}
	}
	
	/**
	 * 处理多条<b>插入、修改、删除</b>语句，并且将其全部置于一个事务中。
	 * 调用{@link TransactionManager#multipleExecute(Map)}进行处理
	 * @param sql 
	 * @param parametes
	 * @return
	 */
	private OperationStatus multipleExecute(Map<String,Object[]> statements) {
		TransactionManager transactionManager = null;
		CcxDB db = getCcxDB();
		try {
			if(db == null) {
				throw new NullPointerException("获取数据库实例失败！");
			}
			transactionManager = new TransactionManager(db);
			return transactionManager.multipleExecute(statements);
		} finally {
			close(db);
		}
	}
	
	/**
	 * 执行查询语句，具体的解析方法直接由{@link DBHandler#parse(ResultSet)}去做，
	 * 然而现在只对{@link E}提供查询的支持，如有其他的查询需求，
	 * 请重写此方法。
	 * 
	 * <b>当返回集合强制转换时，集合中的类型由{@link ResultSetParser}确定。</b>
	 * @param sql
	 * @param parameters
	 * @return
	 */
	protected <E> List<E> queryList(String sql,Object[] parameters, ResultSetParser<E> parser) {
		ResultSet rs = null;
		CcxDB ccxDB = getCcxDB();
		try {
			if(parameters != null) {
				logger.info("SQL:"+ sql +"[parameters:"+objectToString(parameters)+"]");		
			}else {
				logger.info("sql:"+sql);
			}
			rs = ccxDB.executeQuery(sql,parameters);
			List<E> list = parser.parse(rs);
			if(list.size() > 0) {
				return list;
			}
		} catch (Exception e) {
			logger.error("查询集合失败！",e);
		} finally {
			close(ccxDB, rs);
		}
		return null;
	}
	
	/**
	 * 只获取{@link ResultSet}的第一个列
	 * @param sql
	 * @param parameters
	 * @return
	 */
	protected int queryInt(String sql, Object[] parameters) {
		ResultSet rs = null;
		CcxDB ccxDB = getCcxDB();
		try {
			if(parameters != null) {
				logger.info("SQL:"+ sql +"[parameters:"+objectToString(parameters)+"]");		
			}else {
				logger.info("sql:"+sql);
			}
			rs = ccxDB.executeQuery(sql,parameters);
			if(rs.next()) {
				int temp = rs.getInt(1);
				return temp;
			}
			
		} catch (Exception e) {
			logger.error("查询INT值失败！",e);
		} finally {
			close(ccxDB, rs);
		}
		throw new RuntimeException("查询数据库失败");
	}
	
	protected <E> E queryObject(String sql,Object[] parameters,  ResultSetParser<E> parser) {
		ResultSet rs = null;
		CcxDB ccxDB = getCcxDB();
		try {
			if(parameters != null) {
				logger.debug("SQL:"+ sql +"[parameters:"+objectToString(parameters)+"]");		
			}else {
				logger.debug("sql:"+sql);
			}
			rs = ccxDB.executeQuery(sql,parameters);
			E e = null;
			if(rs.next()) {
				e = parser.parseObject(rs);
			}
			return e;
		} catch (Exception e) {
			logger.error("获取对象失败！",e);
		} finally {
			close(ccxDB, rs);
		}
		throw new RuntimeException("查询数据库失败");
	}
	
	/**
	 * 关闭数据库和返回结果集
	 * @param ccxDB
	 * @param rs
	 */
	protected void close(CcxDB ccxDB, ResultSet rs) {
		try {
			rs.close();
			if (ccxDB != null)
				ccxDB.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 关闭数据库
	 * @param ccxDB
	 */
	protected void close(CcxDB ccxDB) {
		try {
			if (ccxDB != null)
				ccxDB.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取数据库实例
	 * @return
	 */
	protected CcxDB getCcxDB() {
		try {
			return DBFactory.getInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private static String objectToString(Object[] object) {
		StringBuffer sb = new StringBuffer();
		for (Object obj : object) {
			sb.append(obj+",");
		}
		return sb.toString();
	}
	
}
